package biz

import (
	"time"

	"github.com/gin-gonic/gin"
	"gitlab1.moolink.net/trade/backend/gen"
	"lab.com/conf"
	"lab.com/consts"
	gen1 "lab.com/gen"
	"lab.com/gen/entity"
	"lab.com/request"
)

type forumBiz struct {
}

// Forum  论坛信息
var Forum = forumBiz{}

// PostAdd 帖子新增
func (forum *forumBiz) PostAdd(c *gin.Context, req request.PostAddReq) (err error) {
	ctx := conf.Span(c, "biz post add", nil)
	postModel := conf.LabGen.ForumPost

	info := &entity.ForumPost{
		Title:      req.Title,
		AuthorID:   req.AuthorID,
		Content:    req.Content,
		CreateTime: time.Now(),
		UpdateTime: time.Now(),
		Status:     consts.PostNormal,
		ReplyNum:   consts.ReplyDefault,
	}

	err = postModel.WithContext(ctx).Create(info)
	if err != nil {
		return err
	}
	return nil
}

// PostEdit 帖子编辑
func (forum *forumBiz) PostEdit(c *gin.Context, req request.PostEditReq) (err error) {
	ctx := conf.Span(c, "biz post edit", nil)
	postModel := conf.LabGen.ForumPost

	info := &entity.ForumPost{
		Title:      req.Title,
		Content:    req.Content,
		UpdateTime: time.Now(),
	}

	_, err = postModel.WithContext(ctx).Select(postModel.Title, postModel.Content, postModel.UpdateTime).Where(postModel.ID.Eq(req.PostID)).Updates(info)
	if err != nil {
		return err
	}
	return nil
}

// PostList 帖子列表
func (forum *forumBiz) PostList(c *gin.Context, req request.PostListReq) (out request.PostListRes, err error) {
	ctx := conf.Span(c, "biz post list", nil)
	postModel := conf.LabGen.ForumPost
	where := []gen.Condition{postModel.Status.Eq(consts.PostNormal)}
	if req.Title != "" {
		where = append(where, postModel.Title.Like("%"+req.Title+"%"))
	}
	info, count, err := postModel.WithContext(ctx).Where(where...).Order(postModel.UpdateTime.Desc()).FindByPage(req.Offset, req.Size)
	if err != nil {
		return out, err
	}
	authorIDs := make([]int, 0)
	for _, val := range info {
		authorIDs = append(authorIDs, val.AuthorID)
	}
	userModel := conf.LabGen.User
	userInfos, err := userModel.WithContext(ctx).Where([]gen.Condition{userModel.ID.In(authorIDs...)}...).Find()
	if err != nil {
		return out, err
	}
	userMap := make(map[int]entity.User)
	for _, val := range userInfos {
		userMap[val.ID] = *val
	}
	list := make([]request.PostBasicInfo, 0, len(info))
	for _, val := range info {
		list = append(list, request.PostBasicInfo{
			PostID:     val.ID,
			Title:      val.Title,
			Content:    val.Content,
			ReplyNum:   val.ReplyNum,
			UpdateTime: val.UpdateTime.Format("2006-01-02 15:04:05"),
			AuthorID:   val.AuthorID,
			AuthorName: userMap[val.AuthorID].Username,
		})
	}
	out.List = list
	out.Count = int(count)
	return out, nil
}

// PostDetail 帖子详情
func (forum *forumBiz) PostDetail(c *gin.Context, req request.PostDetailReq) (out request.PostDetailRes, err error) {
	ctx := conf.Span(c, "biz post detail", nil)
	postModel := conf.LabGen.ForumPost
	where := []gen.Condition{postModel.Status.Eq(consts.PostNormal), postModel.ID.Eq(req.PostID)}

	info, err := postModel.WithContext(ctx).Where(where...).First()
	if err != nil {
		return out, err
	}
	userModel := conf.LabGen.User
	userInfo, err := userModel.WithContext(ctx).Where([]gen.Condition{userModel.ID.Eq(info.AuthorID)}...).First()
	if err != nil {
		return out, err
	}
	out.AuthorID = info.AuthorID
	out.PostID = info.ID
	out.Title = info.Title
	out.Content = info.Content
	out.CreateTime = info.CreateTime.Format("2006-01-02 15:04:05")
	out.UpdateTime = info.UpdateTime.Format("2006-01-02 15:04:05")
	out.ReplyNum = info.ReplyNum
	out.AuthorName = userInfo.Username
	return out, nil
}

// CommentAdd 评论新增
func (forum *forumBiz) CommentAdd(c *gin.Context, req request.CommentAddReq) (err error) {
	ctx := conf.Span(c, "biz comment add", nil)

	if err := conf.LabGen.Transaction(func(tx *gen1.Query) error {
		postCommentModel := tx.PostComment
		info := &entity.PostComment{
			AuthorID:   req.AuthorID,
			Content:    req.Content,
			PostID:     req.PostID,
			Pid:        req.CommentPid,
			TopPid:     req.TopPid,
			CreateTime: time.Now(),
			Status:     consts.PostNormal,
		}

		err = postCommentModel.WithContext(ctx).Create(info)
		if err != nil {
			return err
		}
		//增加帖子回复数
		postModel := conf.LabGen.ForumPost
		_, err = postModel.WithContext(ctx).Where(postModel.ID.Eq(req.PostID)).UpdateSimple(postModel.ReplyNum.Add(1))
		if err != nil {
			return err
		}
		//增加父级评论、顶级评论回复数
		if req.CommentPid != 0 {
			//回复了评论，且评论为顶级评论
			if req.CommentPid == req.TopPid {
				_, err = postCommentModel.WithContext(ctx).Where(postCommentModel.ID.Eq(req.CommentPid)).UpdateSimple(postCommentModel.ReplyNum.Add(1))
				if err != nil {
					return err
				}
			}
			//回复了评论，评论不为顶级评论
			if req.CommentPid != req.TopPid {
				//父级评论增加回复数目
				_, err = postCommentModel.WithContext(ctx).Where(postCommentModel.ID.Eq(req.CommentPid)).UpdateSimple(postCommentModel.ReplyNum.Add(1))
				if err != nil {
					return err
				}
				//顶级评论增加回复数目
				_, err = postCommentModel.WithContext(ctx).Where(postCommentModel.ID.Eq(req.TopPid)).UpdateSimple(postCommentModel.ReplyNum.Add(1))
				if err != nil {
					return err
				}
			}

		}
		return nil
	}); err != nil {
		return err
	}

	return nil
}

// CommentList 帖子评论列表
func (forum *forumBiz) CommentList(c *gin.Context, req request.CommentListReq) (out request.CommentListRes, err error) {
	ctx := conf.Span(c, "biz post comment list", nil)
	postCommentModel := conf.LabGen.PostComment
	where := []gen.Condition{postCommentModel.Status.Eq(consts.PostNormal), postCommentModel.PostID.Eq(req.PostID), postCommentModel.TopPid.Eq(consts.CommentNoPid)}
	//top pid = 0的评论
	info, count, err := postCommentModel.WithContext(ctx).Where(where...).FindByPage(req.Offset, req.Size)
	if err != nil {
		return out, err
	}
	authorIDs := make([]int, 0)
	for _, val := range info {
		authorIDs = append(authorIDs, val.AuthorID)
	}
	userModel := conf.LabGen.User
	userInfos, err := userModel.WithContext(ctx).Where([]gen.Condition{userModel.ID.In(authorIDs...)}...).Find()
	if err != nil {
		return out, err
	}
	userMap := make(map[int]entity.User)
	for _, val := range userInfos {
		userMap[val.ID] = *val
	}
	list := make([]request.CommentBasicInfo, 0, len(info))
	for _, val := range info {
		list = append(list, request.CommentBasicInfo{
			PostID:        val.PostID,
			CommentID:     val.ID,
			Content:       val.Content,
			CreateTime:    val.CreateTime.Format("2006-01-02 15:04:05"),
			AuthorID:      val.AuthorID,
			AuthorName:    userMap[val.AuthorID].Username,
			SubCommentNum: val.ReplyNum,
		})
	}
	out.List = list
	out.Count = int(count)
	return out, nil
}

// CommentUnfoldedList 帖子评论列表（不折叠）
func (forum *forumBiz) CommentUnfoldedList(c *gin.Context, req request.CommentUnfoldedListReq) (out request.CommentUnfoldedListRes, err error) {
	ctx := conf.Span(c, "biz post comment unfolded list", nil)
	postCommentModel := conf.LabGen.PostComment
	where := []gen.Condition{postCommentModel.Status.Eq(consts.PostNormal), postCommentModel.PostID.Eq(req.PostID)}
	info, count, err := postCommentModel.WithContext(ctx).Where(where...).FindByPage(req.Offset, req.Size)
	if err != nil {
		return out, err
	}
	authorIDs := make([]int, 0)
	replyMap := make(map[int]entity.PostComment)
	for _, val := range info {
		authorIDs = append(authorIDs, val.AuthorID)
		replyMap[val.ID] = *val
	}

	userModel := conf.LabGen.User
	userInfos, err := userModel.WithContext(ctx).Where([]gen.Condition{userModel.ID.In(authorIDs...)}...).Find()
	if err != nil {
		return out, err
	}
	userMap := make(map[int]entity.User)
	for _, val := range userInfos {
		userMap[val.ID] = *val
	}

	list := make([]request.CommentUnfoldedBasicInfo, 0, len(info))
	for _, val := range info {
		list = append(list, request.CommentUnfoldedBasicInfo{
			PostID:          val.PostID,
			CommentID:       val.ID,
			Content:         val.Content,
			CreateTime:      val.CreateTime.Format("2006-01-02 15:04:05"),
			AuthorID:        val.AuthorID,
			AuthorName:      userMap[val.AuthorID].Username,
			SubCommentNum:   val.ReplyNum,
			ReplyAuthorID:   replyMap[val.Pid].AuthorID,
			ReplyAuthorName: userMap[replyMap[val.Pid].AuthorID].Username,
		})
	}
	out.List = list
	out.Count = int(count)
	return out, nil
}

// CommentInnerList 评论区内部列表
func (forum *forumBiz) CommentInnerList(c *gin.Context, req request.CommentInnerListReq) (out request.CommentUnfoldedListRes, err error) {
	ctx := conf.Span(c, "biz post comment inner list", nil)
	postCommentModel := conf.LabGen.PostComment
	where := []gen.Condition{postCommentModel.Status.Eq(consts.PostNormal), postCommentModel.TopPid.Eq(req.CommentID)}
	info, count, err := postCommentModel.WithContext(ctx).Where(where...).FindByPage(req.Offset, req.Size)
	if err != nil {
		return out, err
	}
	authorIDs := make([]int, 0)
	replyMap := make(map[int]entity.PostComment)
	for _, val := range info {
		authorIDs = append(authorIDs, val.AuthorID)
		replyMap[val.ID] = *val
	}

	userModel := conf.LabGen.User
	userInfos, err := userModel.WithContext(ctx).Where([]gen.Condition{userModel.ID.In(authorIDs...)}...).Find()
	if err != nil {
		return out, err
	}
	userMap := make(map[int]entity.User)
	for _, val := range userInfos {
		userMap[val.ID] = *val
	}

	list := make([]request.CommentUnfoldedBasicInfo, 0, len(info))
	for _, val := range info {
		//回复当前评论，不显示@xxx
		var replyAuthorID int
		var replyAuthorName string
		if val.Pid == req.CommentID {
			replyAuthorID = 0
			replyAuthorName = ""
		} else {
			replyAuthorID = replyMap[val.Pid].AuthorID
			replyAuthorName = userMap[replyMap[val.Pid].AuthorID].Username
		}
		list = append(list, request.CommentUnfoldedBasicInfo{
			PostID:          val.PostID,
			CommentID:       val.ID,
			Content:         val.Content,
			CreateTime:      val.CreateTime.Format("2006-01-02 15:04:05"),
			AuthorID:        val.AuthorID,
			AuthorName:      userMap[val.AuthorID].Username,
			SubCommentNum:   val.ReplyNum,
			ReplyAuthorID:   replyAuthorID,
			ReplyAuthorName: replyAuthorName,
		})
	}
	out.List = list
	out.Count = int(count)
	return out, nil
}
